use std::{fs::File, os::raw::c_void};
use std::ffi::CStr;

use ash::vk;

use crate::{vulkan::VkConfig, VK_LOGP, VK_LOGV, VK_LOGI, VK_LOGW, VK_LOGE, VK_CHECK_UNSAFE};

use super::VkDebugUtils;
use ash::extensions::ext::DebugUtils as ExtDebugUtilsFnSet;

/// 错误回调函数
pub(crate) unsafe extern "system" fn vk_debug_utils_callback(
    message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
    message_type: vk::DebugUtilsMessageTypeFlagsEXT,
    p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
    _p_user_data: *mut c_void
) -> vk::Bool32 {
    let type_str = match message_type {
        vk::DebugUtilsMessageTypeFlagsEXT::DEVICE_ADDRESS_BINDING   => "device_address_binding",
        vk::DebugUtilsMessageTypeFlagsEXT::GENERAL                  => "General",
        vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE              => "Performace",
        vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION               => "Validation",
        _ => {"None"}
    };
    
    match message_severity {
        vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE      => VK_LOGV!("[{}] {:?}", type_str, CStr::from_ptr((*p_callback_data).p_message)),
        vk::DebugUtilsMessageSeverityFlagsEXT::INFO         => VK_LOGI!("[{}] {:?}", type_str, CStr::from_ptr((*p_callback_data).p_message)),
        vk::DebugUtilsMessageSeverityFlagsEXT::WARNING      => VK_LOGW!("[{}] {:?}", type_str, CStr::from_ptr((*p_callback_data).p_message)),
        vk::DebugUtilsMessageSeverityFlagsEXT::ERROR        => VK_LOGE!("[{}] {:?}", type_str, CStr::from_ptr((*p_callback_data).p_message)),
        _                                                   => VK_LOGE!("[{}] {:?}", type_str, CStr::from_ptr((*p_callback_data).p_message))
    };

    vk::FALSE
}

impl VkDebugUtils {
    pub fn new(vk_config: &VkConfig, vk_entry: &ash::Entry, vk_instance: &ash::Instance) -> Self {
        let function_set = ExtDebugUtilsFnSet::new(vk_entry, vk_instance);

        Self {
            handler         : {
                let debug_utils_ci = vk_config.get_debug_utils_ci();
                match VK_CHECK_UNSAFE!(function_set.create_debug_utils_messenger(&debug_utils_ci, None)) {
                    Some(inner_value) => inner_value,
                    None => VK_LOGP!("Failed to create_debug_utils_messenger")
                }
            },
            function_set    : function_set
        }
    }
}